package ui.componentes;

import javax.swing.*;
import java.awt.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.io.*;
import java.util.*;
import javax.swing.text.*;
public class ReorderableJList extends JList 
implements DragSourceListener, DropTargetListener, DragGestureListener {

static DataFlavor localObjectFlavor;

static {
    try {
        localObjectFlavor = new DataFlavor (DataFlavor.javaJVMLocalObjectMimeType);
    } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } 
} 
static DataFlavor[] supportedFlavors = { localObjectFlavor }; 
DragSource dragSource; 
DropTarget dropTarget; 
Object dropTargetCell; 
int draggedIndex = -1;

public ReorderableJList () {
    super();
    setCellRenderer (new ReorderableListCellRenderer());
    setModel (new DefaultListModel());
    dragSource = new DragSource();
    DragGestureRecognizer dgr =
        dragSource.createDefaultDragGestureRecognizer (this,
                                   DnDConstants.ACTION_MOVE,
                                                       this);
    dropTarget = new DropTarget (this, this);
}

public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
    return -1;
}

// DragGestureListener
public void dragGestureRecognized (DragGestureEvent dge) {
    // find object at this x,y
    Point clickPoint = dge.getDragOrigin();
    int index = locationToIndex(clickPoint);
    if (index == -1)
        return;
    Object target = getModel().getElementAt(index);
    Transferable trans = new RJLTransferable (target);
    draggedIndex = index;
    dragSource.startDrag (dge,Cursor.getDefaultCursor(),
                          trans, this);
}
// DragSourceListener events
public void dragDropEnd (DragSourceDropEvent dsde) {
   dropTargetCell = null;
   draggedIndex = -1;
   repaint();
}
public void dragEnter (DragSourceDragEvent dsde) {}
public void dragExit (DragSourceEvent dse) {}
public void dragOver (DragSourceDragEvent dsde) {}
public void dropActionChanged (DragSourceDragEvent dsde) {}
// DropTargetListener events
public void dragEnter (DropTargetDragEvent dtde) {
    if (dtde.getSource() != dropTarget)
        dtde.rejectDrag();
    else {
        dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
    }
}
public void dragExit (DropTargetEvent dte) {}
// dragOver() listed below
// drop() listed below
public void dropActionChanged (DropTargetDragEvent dtde) {}

class RJLTransferable implements Transferable { 
    Object object; 
    public RJLTransferable (Object o) {
        object = o;
    }
    public Object getTransferData(DataFlavor df)
        throws UnsupportedFlavorException, IOException {
        if (isDataFlavorSupported (df))
            return object;
        else
           throw new UnsupportedFlavorException(df);
    }
    public boolean isDataFlavorSupported (DataFlavor df) {
        return (df.equals (localObjectFlavor));
    }
    public DataFlavor[] getTransferDataFlavors () {
        return supportedFlavors; } 
}

public void dragOver (DropTargetDragEvent dtde) { 
    // figure out which cell it's over, no drag to self    
    if (dtde.getSource() != dropTarget)
        dtde.rejectDrag();
    Point dragPoint = dtde.getLocation();
    int index = locationToIndex (dragPoint);
    if (index == -1)
        dropTargetCell = null; 
    else        
        dropTargetCell = getModel().getElementAt(index);    
    repaint(); 
}

class ReorderableListCellRenderer 
extends DefaultListCellRenderer { 
boolean isTargetCell; 
boolean isLastItem;    
public ReorderableListCellRenderer() {
    super();
}
public Component getListCellRendererComponent (JList list,
                                               Object value, 
                                               int index, 
                                               boolean isSelected,                                                  boolean hasFocus) {
    isTargetCell = (value == dropTargetCell);
    isLastItem = (index == list.getModel().getSize()-1);
    boolean showSelected = isSelected &
                          (dropTargetCell == null);
    return super.getListCellRendererComponent (list, value, 
                                               index, showSelected,                                                 
                                               hasFocus);
}
public void paintComponent (Graphics g) {
    super.paintComponent(g);
    if (isTargetCell) {
        g.setColor(Color.black);            
        g.drawLine (0, 0, getSize().width, 0); 
    } 
 } 
}

public void drop (DropTargetDropEvent dtde) {    
    if (dtde.getSource() != dropTarget) {   
        dtde.rejectDrop(); 
        return;
    }
    Point dropPoint = dtde.getLocation();
    int index = locationToIndex (dropPoint);

    boolean dropped = false;
    try {
        if ((index == -1) || (index == draggedIndex)) {

            dtde.rejectDrop();
            return;
        }
        dtde.acceptDrop (DnDConstants.ACTION_MOVE);

        Object dragged =
           dtde.getTransferable().getTransferData(localObjectFlavor);
        // move items - note that indicies for insert will 
        // change if [removed] source was before target 

        boolean sourceBeforeTarget = (draggedIndex < index); 

         DefaultListModel mod = (DefaultListModel) getModel(); 
        mod.remove (draggedIndex); 
        mod.add ((sourceBeforeTarget ? index-1 : index), dragged); 
        dropped = true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    dtde.dropComplete (dropped);
}

}